﻿/*
 *	Copyright (c) 2008..11 by SiModel.n Baer
 * 
 *  You may use this code for whatever you want.
 */

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Db.DAL
{
	/// <summary>
	/// Helper class for hiding/showing the taskbar and startmenu on
	/// Windows XP and Vista.
	/// </summary>
	public static class Taskbar
	{
		[DllImport("user32.dll")]
		private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); 
		[DllImport("user32.dll", CharSet = CharSet.Auto)]
		private static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);
		[DllImport("user32.dll", SetLastError = true)]
		private static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
		[DllImport("user32.dll", SetLastError = true)]
		private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string windowTitle);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr parentHwnd, IntPtr childAfterHwnd, IntPtr className, string windowText);
        [DllImport("user32.dll")]
		private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
		[DllImport("user32.dll")]
		private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);

		private const int SW_HIDE = 0;
		private const int SW_SHOW = 5;

		private const string VistaStartMenuCaption = "Start";
		private static IntPtr vistaStartMenuWnd = IntPtr.Zero;
		private delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);

		/// <summary>
		/// Show the taskbar.
		/// </summary>
		public static void Show()
		{
			SetVisibility(true);
		}

		/// <summary>
		/// Hide the taskbar.
		/// </summary>
		public static void Hide()
		{
			SetVisibility(false);
		}

		/// <summary>
		/// Sets the visibility of the taskbar.
		/// </summary>
		public static bool Visible
		{
			set { SetVisibility(value); }
		}

		/// <summary>
		/// Hide or show the Windows taskbar and startmenu.
		/// </summary>
		/// <param name="show">true to show, false to hide</param>
		private static void SetVisibility(bool show)
		{
			// get taskbar window
			IntPtr taskBarWnd = FindWindow("Shell_TrayWnd", null);

			// try it the WinXP way first...
			IntPtr startWnd = FindWindowEx(taskBarWnd, IntPtr.Zero, "Button", "Start");

            if (startWnd == IntPtr.Zero)
            {
                // try an alternate way, as mentioned on CodeProject by Earl Waylon Flinn
                startWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, (IntPtr)0xC017, "Start");
            }

			if (startWnd == IntPtr.Zero)
			{
				// ok, let's try the Vista easy way...
				startWnd = FindWindow("Button", null);

				if (startWnd == IntPtr.Zero)
				{
					// no chance, we need to to it the hard way...
					startWnd = GetVistaStartMenuWnd(taskBarWnd);
				}
			}
			
			ShowWindow(taskBarWnd, show ? SW_SHOW : SW_HIDE);
			ShowWindow(startWnd, show ? SW_SHOW : SW_HIDE);
		}

		/// <summary>
		/// Returns the window handle of the Vista start menu orb.
		/// </summary>
		/// <param name="taskBarWnd">windo handle of taskbar</param>
		/// <returns>window handle of start menu</returns>
		private static IntPtr GetVistaStartMenuWnd(IntPtr taskBarWnd)
		{
			// get process that owns the taskbar window
			int procId;
			GetWindowThreadProcessId(taskBarWnd, out procId);

			Process p = Process.GetProcessById(procId);
			if (p != null)
			{
				// enumerate all threads of that process...
				foreach (ProcessThread t in p.Threads)
				{
					EnumThreadWindows(t.Id, MyEnumThreadWindowsProc, IntPtr.Zero);
				}
			}
			return vistaStartMenuWnd;
		}

		/// <summary>
		/// Callback method that is called from 'EnumThreadWindows' in 'GetVistaStartMenuWnd'.
		/// </summary>
		/// <param name="hWnd">window handle</param>
		/// <param name="lParam">parameter</param>
		/// <returns>true to continue enumeration, false to stop it</returns>
		private static bool MyEnumThreadWindowsProc(IntPtr hWnd, IntPtr lParam)
		{
			StringBuilder buffer = new StringBuilder(256);
			if (GetWindowText(hWnd, buffer, buffer.Capacity) > 0)
			{
				Console.WriteLine(buffer);
				if (buffer.ToString() == VistaStartMenuCaption)
				{
					vistaStartMenuWnd = hWnd;
					return false;
				}
			}
			return true;
		}
	}
}
